#ifndef	_PACKER_H_
#define	_PACKER_H_

#include <vector>
#include <algorithm>
#include <string>
#include <iterator>
#include <cmath>

#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/random_number_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/shared_ptr.hpp>

#include <CGAL/Timer.h>
#include <CGAL/create_offset_polygons_2.h>

#include <Geex/basics/types.h>
#include <Geex/basics/file_system.h>
#include <glut_viewer/glut_viewer.h>

#include "../common/particle_circle.h"
#include "../common/containers.h"
#include "../common/potential_energy.h"
#include "../common/circle_union.h"
#include "../common/bin_packing.h"
#include "../common/polytope.h"
#include "common/circle_system.h"

namespace Polygon_particle
{
	using namespace Packing_common;

	class Packing_graphics;

	class Packer 
	{
		friend class Packing_graphics;

	public:
		
		Packer(const std::string& polygon_fn, const std::string& debug_fn, double coverage_rate = 0.7) ;
		~Packer();
		/* set methods */
	
		/* query methods */
		static Packer* instance() { return instance_ ; }

		inline unsigned int nb_polytopes() const { return polygon_set.size(); }
		/* debug */
		void trace();
		void hand_select(double mouse_x, double mouse_y);
		void hand_move(double mouse_x, double mouse_y);
		void print_polygons() ;
		/* computation */
		double energy_minimize();
		void perturb() ;
		void pack(unsigned int nb_trials = 50);
		void shuffle();

		/* miscellaneous */
		void get_bbox(Geex::real& x_min, Geex::real& y_min, Geex::real& z_min, Geex::real& x_max, Geex::real& y_max, Geex::real& z_max);

	private:
		void compute_bounding_circles();

	private:

		static Packer* instance_ ;

		std::vector<Packing_polygon*> polygon_set;
		Rectangular_box *rbox;

		double min_energy;
		double total_volume;
		double max_rate;

		boost::random::mt19937 rand_gen;

		// energy objects
		std::vector<Circle_union> cus;

		//debug
		std::list< std::list<Parameter> > iter_trans;
		std::vector<Packing_polygon> mirror_polygons;
		std::vector<Circle_union> mirror_unions;
		unsigned int select_no;
	} ;


}

#endif